package com.saianfu.flowable


import org.flowable.engine.*

import org.flowable.engine.runtime.ProcessInstance
import org.flowable.engine.task.Comment
import org.flowable.task.api.Task
import org.flowable.task.api.TaskQuery

import org.flowable.task.api.history.HistoricTaskInstance
import java.io.ByteArrayOutputStream

import java.util.*


/**
 * Flowable的扩展类
 */
object FlowableEx {

    /**
     * 部署bpmn文件
     */
    fun deploy(repositoryService: RepositoryService, bpmnFileUrl: String) {
        repositoryService.createDeployment().addClasspathResource(bpmnFileUrl).deploy()
    }

    /**
     * 开启一个流程
     */
    fun startProcessInstanceByKey(runtimeService: RuntimeService, processDefinitionKey: String, variables: Map<String, Any?>? = mutableMapOf()): ProcessInstance {
        val pi = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables)
        return pi
    }

    /**
     * 判断流程实例是否运行
     */
    fun isProcessRunning(runtimeService: RuntimeService, instanceId: String): Boolean {
        val execution = runtimeService.createExecutionQuery().processInstanceId(instanceId).list()
        return execution.isNotEmpty()
    }

    /**
     * 挂起流程实例，流程不能进行其他操作，后续可以激活
     */
    fun suspendProcessInstance(runtimeService: RuntimeService, instanceId: String) {
        runtimeService.suspendProcessInstanceById(instanceId)
    }

    /**
     *激活流程实例，和挂起相反
     */
    fun activateProcessInstance(runtimeService: RuntimeService, instanceId: String) {
        runtimeService.activateProcessInstanceById(instanceId)
    }

    /**
     * 撤销流程实例，数据会保存至历史表
     */
    fun deleteProcessInstance(runtimeService: RuntimeService, instanceId: String, deleteReason: String?) {
        runtimeService.deleteProcessInstance(instanceId, deleteReason ?: "")
    }

    /**
     * 获取历史任务列表
     */
    fun listHistoricTask(historyService: HistoryService, instanceId: String, start: Int, limit: Int): List<HistoricTaskInstance> {
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(instanceId)
                .orderByTaskCreateTime()
                .desc()
                .listPage(start, limit)
    }

    /**
     *活动任务
     */
    fun activeTask(historyService: HistoryService, instanceId: String): HistoricTaskInstance {
        return historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceId).unfinished().singleResult()
    }

    fun activeTask2(taskService: TaskService, instanceId: String): List<Task> {
        val taskList = taskService.createTaskQuery().processInstanceId(instanceId).list()
        return taskList
    }


    /**
     * 获取流程审核进度图
     */
    fun getActivityDiagram(proceeEngine: ProcessEngine, processDefinitionId: String, instanceId: String): ByteArray? {
        val repositoryService: RepositoryService = proceeEngine.repositoryService
        val historyService: HistoryService = proceeEngine.historyService

        //获得已经办理的历史节点
        val activityInstances = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .orderByHistoricActivityInstanceStartTime()
                .asc()
                .list()
        val activties: MutableList<String> = ArrayList()
        val flows: MutableList<String> = ArrayList()

        for (activityInstance in activityInstances) {
            if ("sequenceFlow" == activityInstance.activityType) {
                //需要高亮显示的连接线
                flows.add(activityInstance.activityId)
            } else {
                //需要高亮显示的节点
                activties.add(activityInstance.activityId)
            }
        }

        try {
            //根据modelId或者BpmnModel
            val bpmnModel = repositoryService.getBpmnModel(processDefinitionId)
            val configuration = proceeEngine.processEngineConfiguration
            val generator = configuration.processDiagramGenerator
            val inputStream = generator.generateDiagram(bpmnModel, "jpg",
                    activties, flows, configuration.activityFontName,
                    configuration.labelFontName, configuration.annotationFontName, configuration.classLoader,
                    1.0, true)
            val os = ByteArrayOutputStream()
            val buf = ByteArray(1024)
            var len = 0
            do {
                len = inputStream.read(buf)
                if (len != -1) {
                    os.write(buf, 0, len)
                }
            } while (len != -1)

            return os.toByteArray()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 完成任务
     */
    fun completeTask(taskService: TaskService, taskId: String, variables: Map<String, Any?>?) {
        taskService.complete(taskId, variables)
    }

    /**
     * 转办任务
     */
    fun transferTask(taskService: TaskService, taskId: String, curUserId: String, acceptUserId: String) {
        taskService.setOwner(taskId, curUserId)
        taskService.setAssignee(taskId, acceptUserId)
    }


    /**
     * 委派任务：是将任务节点分给其他人处理，等其他人处理好之后，委派任务会自动回到委派人的任务中
     */
    fun delegateTask(taskService: TaskService, taskId: String, curUserId: String, acceptUserId: String) {
        taskService.setOwner(taskId, curUserId)
        taskService.delegateTask(taskId, acceptUserId)
    }

    /**
     * 被委派任务的办理:   办理完成后，委派任务会自动回到委派人的任务中
     */
    fun resolveTask(taskService: TaskService, taskId: String, variables: Map<String, Any?>?) {
        taskService.resolveTask(taskId, variables)
    }

    /**
     * 添加注释
     */
    fun addComment(taskService: TaskService, taskId: String, instanceId: String, message: String?) {
        taskService.addComment(taskId, instanceId, message)
    }

    /**
     * 获取注释列表
     */
    fun listComment(taskService: TaskService, taskId: String): List<Comment> {
        return taskService.getTaskComments(taskId)
    }

    /**
     * 签收任务
     * 签收:一般情况就是多个候选人，或者候选组的情况下，要先把这个任务签收下来，以免别人又做了同样的任务。
     * 反签收：就是把执行人设置为空
     */
    fun claim(taskService: TaskService, taskId: String, userId: String) {
        taskService.claim(taskId, userId)
    }

    /**
     * 反签收任务
     */
    fun unclaim(taskService: TaskService, taskId: String) {
        taskService.unclaim(taskId)
    }

    /**
     * 创建任务查询句柄
     */
    private fun buildTaskQueryByVariables(taskService: TaskService, args: Map<String, Any?>): TaskQuery {
        val taskQuery = taskService.createTaskQuery()
        args.forEach { (k, v) ->
            taskQuery.processVariableValueEquals(k, v)
        }
        return taskQuery
    }

    /**
     * 根据条件查询任务
     * userType： 0 查询参与者，1查询执行者，2参与者和执行者均可查
     */
    fun taskByCondition(taskService: TaskService, variables: Map<String, Any?>, candidateUser: String, userType: Int, start: Int, limit: Int): List<Task> {
        val taskQuery = buildTaskQueryByVariables(taskService, variables)
        when (userType) {
            0 -> {
                taskQuery.taskCandidateUser(candidateUser)
            }
            1 -> {
                taskQuery.taskAssigneeLikeIgnoreCase(candidateUser)
            }
            else -> {
                taskQuery.taskCandidateOrAssigned(candidateUser)
            }
        }
        return taskQuery.orderByTaskPriority().desc()
                .orderByTaskCreateTime().asc()
                .listPage(start, limit)

    }

    /**
     * 根据条件查询任务
     * userType： 0 查询参与者，1查询执行者，2参与者和执行者均可查
     */
    fun countTaskByCondition(taskService: TaskService, variables: Map<String, Any?>, candidateUser: String, userType: Int): Long {
        val taskQuery = buildTaskQueryByVariables(taskService, variables)
        when (userType) {
            0 -> {
                taskQuery.taskCandidateUser(candidateUser)
            }
            1 -> {
                taskQuery.taskAssigneeLikeIgnoreCase(candidateUser)
            }
            else -> {
                taskQuery.taskCandidateOrAssigned(candidateUser)
            }
        }
        return taskQuery.count()

    }

    /**
     * 查询任务的参数
     */
    fun listVariableByTaskId(taskService: TaskService, taskId: String): Map<String, Any?> {
        return taskService.getVariables(taskId)
    }


}